﻿package ygg.printer
{
	import j.sus2maj7.printer.*;
	import j.sus2maj7.context.*;
	import j.sus2maj7.util.*;
	import flash.utils.ByteArray;
	
	import ygg.encoding.swf.abc.*;
	import ygg.encoding.swf.abc.object.*;
	import ygg.encoding.swf.abc.constant.*;
	
	public class ClassPrinter extends TraitPrinter
	{
		
		public function ClassPrinter()
		{
			super();
		}
		override public function printToString(o:*, context:IContext=null):String
		{
			return printToStringB(o, context).toString();
		}
		override public function printToStringB(o:*, context:IContext=null):StringBuilder
		{
			return print(Class_(o), AbcContext(context.vars.abcContext), PrinterContext(context) );
		}
		
		private function print(c:Class_, context:AbcContext, pc:PrinterContext ):StringBuilder
		{//trace('cl print');
			var cPool:ConstantPool = context.constantPool;
			var sb:StringBuilder = (pc.sb == null) ? new StringBuilder() : pc.sb;
			var indent:String = pc.indent || '';
			var tab:String = pc.tab || '    ';
			
			if (c.metadata)
			{
				var md:*;
				for each (md in c.metadata)
				{
					sb.append(indent + md + "\n")
				}
			}
			
			var def:String = '';
			var i:Instance = c.instance;
			//sb.append('/*'+ i.usesProtected + ' ' + i.protectedNs +'*/\n');
			if (i.isInterface)
			{
				def += "interface ";
			}
			else
			{
				if (!i.isSealed) def += "dynamic ";
				
				if (i.isFinal) def += "final ";
				
				def += c.accessSpecifier;
				
				def += " class ";
			}
			
			//package if class is private no package
			if (c.accessSpecifier != AccessSpecifier.PRIVATE)
			{
				sb.append('package ' + c.packageName + '\n{\n' );
				indent += tab;
			}
			
			//DO IMPORTS HERE - avilable only after parsing method bodies
			
			
			sb.append(indent + def + i.name);
			
			if ( i.superMultiname.name != '*' && i.superMultiname.name != 'Object')
				sb.append( " extends " + i.superMultiname.name) ;
			
			var oldIndent:String = indent;
			
			indent += tab;
			
			if (i.interfaces.length > 0)
			{
				for each (var mn:Multiname in i.interfaces)
				{
					sb.append(" implements " + mn.name);
				}
				
			}
			sb.append("\n" + oldIndent + "{\n" + indent);
			
			var ipf:IPrinterFactory = pc.vars.factory || new AbcPrinterFactory();
			var ip:IPrinter;
		
			//print static constructor
			/*
			pc.indent = indent;
			ip = ipf.getPrinter(c.init);
			sb.append( ip.printToString( c.init, pc) );
			//*/
			var t:Trait;
			
			//trace('cl print statics');
			var count:uint;
			//print static members
			pc.indent = indent;
			for each (t in c.variables)
			{
				if (t)
				{
					ip = ipf.getPrinter(t);
					sb.append( ip.printToString(t, pc) );
					count++;
				}
			}
			//trace('cl print constants');
			for each (t in c.constants)
			{
				if (t)
				{
					ip = ipf.getPrinter(t);
					sb.append( ip.printToString(t, pc) );
					count++;
				}
			}
			//trace('cl print methods');
			
			if (count) sb.append('\n' + indent );
			count = 0;
			for each (t in c.methods)
			{
				if (t)
				{
					ip = ipf.getPrinter(t);
					sb.append( ip.printToString(t, pc) );
					count++;
				}
			}
			//trace('cl print functions');
			for each (t in c.functions)
			{
				if (t)
				{
					ip = ipf.getPrinter(t);
					sb.append( ip.printToString(t, pc) );
					count++;
				}
			}
			
			//trace('cl print iv');
			for each (t in i.variables)
			{
				if (t)
				{
					ip = ipf.getPrinter(t);
					sb.append( ip.printToString(t, pc) );
					count++;
				}
			}
			//trace('cl print ic');
			for each (t in i.constants)
			{
				if (t)
				{
					ip = ipf.getPrinter(t);
					sb.append( ip.printToString(t, pc) );
					count++;
				}
			}
			
			if (count) sb.append('\n' + indent );
			count = 0;
			if (!i.isInterface)
			{
				//trace('cl print instance');
				//print instance constructor
				ip = ipf.getPrinter(i.init);
				sb.append( ip.printToString( i.init, pc ) );
				count++;
			}
			
			if (count) sb.append('\n' + indent );
			count = 0;
			//trace('cl print im');
			for each (t in i.methods)
			{
				if (t)
				{
					ip = ipf.getPrinter(t);
					sb.append( ip.printToString(t, pc) );
					count++;
				}
			}
			//trace('cl print if');
			for each (t in i.functions)
			{
				if (t)
				{
					ip = ipf.getPrinter(t);
					sb.append( ip.printToString(t, pc) );
					count++;
				}
			}
			
			ipf.destroy();
			if (ip) ip.destroy();
			
			//class close
			sb.append('\n' + oldIndent + '}\n');
			
			//package close
			if (c.accessSpecifier != AccessSpecifier.PRIVATE)
			{
				sb.append('}\n');
			}
			
			//trace('e cl print');
			return sb;
			
		}
	}
}